#!/usr/bin/env python3 
# -*- coding: utf-8 -*-
import io
import sys
import logging
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8')

from collections import Iterator


#try...except...finally...的错误处理机制

try:
    print('try...')
    r = 10 / 0
    print('result:', r)
except ZeroDivisionError as e:
    print('except:', e)
finally:
    print('finally...')
print('END')

#try来运行这段代码，如果执行出错，则后续代码不会继续执行，
#而是直接跳转至错误处理代码，即except语句块，执行完except后，
#如果有finally语句块，则执行finally语句块，至此，执行完毕。

#Python的错误其实也是class，所有的错误类型都继承自BaseException，
#所以在使用except时需要注意的是，它不但捕获该类型的错误，还把其子类也“一网打尽”。比如：

def foo():
    r = 10 / 0
    if r==(-1):
        return (-1)
    # do something
    return r

try:
    foo()
except ValueError as e:
    print('ValueError')
except UnicodeError as e:
    print('UnicodeError')

#第二个except永远也捕获不到UnicodeError，因为UnicodeError是ValueError的子类，如果有，也被第一个except给捕获了。



#记录错误
#如果不捕获错误，自然可以让Python解释器来打印出错误堆栈，但程序也被结束了。
#既然我们能捕获错误，就可以把错误堆栈打印出来，然后分析错误原因，同时，让程序继续执行下去。

#Python内置的logging模块可以非常容易地记录错误信息：
def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    try:
        bar('0')
    except Exception as e:
        logging.exception(e)

main()
print('END')

#抛出错误
#因为错误是class，捕获一个错误就是捕获到该class的一个实例。因此，错误并不是凭空产生的，而是有意创建并抛出的。
#Python的内置函数会抛出很多类型的错误，我们自己编写的函数也可以抛出错误。

#如果要抛出错误，首先根据需要，可以定义一个错误的class，选择好继承关系，然后，用raise语句抛出一个错误的实例：

class FooError(ValueError):
    pass

def foo(s):
    n = int(s)
    if n==0:
        raise FooError('invalid value: %s' % s)
    return 10 / n

foo('0')
